/*
 * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef VIRTNET_VQ_H
#define VIRTNET_VQ_H

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <net/ethernet.h>

#include <snap.h>
#include <snap_virtio_net.h>
#include <snap_dma.h>
#include <snap_virtio_common_ctrl.h>
#include <snap_virtio_net_ctrl.h>

#include "virtnet_util.h"

#ifdef __cplusplus
extern "C" {
#endif

#define VIRTIO_DESC_REQ_MAX_DESC	(6)
#define VIRTIO_MAX_MSIX			(64)
#define VIRTNET_MAC_TABLE_ENTRIES	(64)
#define VIRTNET_HASH_KEY_LEN		(40)
#define VIRTNET_MAX_VLAN		(1 << 12)


struct virtnet_device;

enum {
	MLX5_INLINE_Q_TYPE_RQ = 0x0,
	MLX5_INLINE_Q_TYPE_VIRTQ = 0x1,
};

enum queue_period_mode {
	VIRTQ_PERIOD_DEFAULT	= 0,
	VIRTQ_PERIOD_UPON_EVENT = 1,
	VIRTQ_PERIOD_UPON_CQE	= 2,
};

struct virtnet_vq_desc {
	uint64_t addr;
	uint32_t len;
#define VIRTQ_DESC_F_NEXT 1
#define VIRTQ_DESC_F_WRITE 2
#define VIRTQ_DESC_F_INDIRECT 4
	uint16_t flags;
	uint16_t next;
}__attribute__((packed));

struct virtnet_desc_tunnel_request_split {
	uint16_t avail_index;
	uint16_t num_desc;
	uint64_t reserved;
	struct virtnet_vq_desc desc[VIRTIO_DESC_REQ_MAX_DESC];
}__attribute__((packed));

struct virtnet_desc_tunnel_response_split {
	uint16_t avail_index;
	uint16_t reserved;
	uint32_t len;
}__attribute__((packed));

struct virtnet_desc_tunnel_request_packed {
	uint16_t desc_index;
	uint16_t num_desc;
	uint64_t reserved;
	uint16_t desc_num[VIRTIO_DESC_REQ_MAX_DESC];
}__attribute__((packed));

struct virtnet_desc_tunnel_response_packed {
	uint16_t buffer_index;
	uint16_t reserved;
	uint16_t num_desc;
	uint32_t len;
}__attribute__((packed));

union virtnet_desc_tunnel_request {
	struct virtnet_desc_tunnel_request_packed packed;
	struct virtnet_desc_tunnel_request_split split;
};

union virtnet_desc_tunnel_response {
	struct virtnet_desc_tunnel_response_packed packed;
	struct virtnet_desc_tunnel_response_split split;
};

struct virtnet_qp {
	union virtnet_desc_tunnel_request *reqs;
	/* request mr saved in dma helper. */
	union virtnet_desc_tunnel_response *resp;
	struct ibv_mr *tx_mr;
	/* Buffer for rdma read/write */
	struct ibv_mr *rdma_mr;
	uint8_t *rdma_buf;
	size_t rdma_buf_len;
	struct virtnet_epoll_data cb_data;
	struct snap_dma_ibv_qp *dma;
};

struct virtnet_ctrl_qp {
	struct snap_dma_q *dma;
	struct virtnet_qp sw; /* for SF and desc tunnel */
	struct virtnet_qp fw; /* for fw ACE */
};

typedef int
(*virtent_vq_tunnel_recv_cb)(struct virtnet_device *dev,
			     struct virtnet_qp *qp,
			     union virtnet_desc_tunnel_request *req);

struct virtnet_vq {
	struct snap_virtio_net_queue *snap_q;
};

struct virtnet_queue_period {
	enum queue_period_mode mode;
	uint16_t period;
	uint16_t max_count;
};

struct virtnet_iovec {
	void *iov_base;
	size_t iov_len;
};

typedef uint64_t hwaddr;

struct virtnet_vq_elem {
	unsigned int index;
	unsigned int len;
	unsigned int ndescs;
	unsigned int out_num;
	unsigned int in_num;
	hwaddr *in_addr; /*< array of read-only descriptor address.*/
	hwaddr *out_addr; /*< array of writable descriptor address. */
	struct virtnet_iovec *in_lbuf; /*< array of local buffer for mapped
					 read-only desc. */
	struct virtnet_iovec *out_lbuf; /*< array of local buffer for mapped
					  writable desc. */
};

struct virtnet_vlan_table_entry {
	void *dev_flow; /*< device's flow handle. */
};

struct virtnet_vlan_table {
	uint32_t in_use;
	struct virtnet_vlan_table_entry *entries;
};

struct virtnet_mac_table_entry {
	uint8_t addr[ETH_ALEN];
	void *dev_flow; /*< device's flow handle. */
};

struct virtnet_mac_table {
	uint32_t in_use;
	uint32_t first_multi;
	uint8_t multi_overflow;
	uint8_t uni_overflow;
	struct virtnet_mac_table_entry *entries;
};

int virtnet_vq_eth_create(struct virtnet_device *dev, int idx);
int virtnet_vq_tunnel_create(struct virtnet_device *dev, int idx);
int virtnet_vq_tunnel_epoll(struct virtnet_device *dev);
int virtnet_vqs_create(struct virtnet_device *dev);
void virtnet_vqs_destroy(struct virtnet_device *dev);
int virtnet_vqs_update_period(struct virtnet_device *dev);

void
virtnet_vq_ctrl_cmds_parse(struct virtnet_device *dev, struct virtnet_qp *qp,
			   union virtnet_desc_tunnel_request *req);

#ifdef __cplusplus
}
#endif

#endif
